package com.cy.pj.common.aspect;

import com.cy.pj.common.annotation.ClearCache;
import com.cy.pj.common.annotation.RequiredCache;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @Author YuBaoFu
 * @create 2025/06/09
 * @description
 */
@Order(1)
@Aspect
@Component
public class SysCacheAspect {

    private Map<String,Object> cache = new HashMap<>();

    @Pointcut("@annotation(com.cy.pj.common.annotation.RequiredCache)")
    public void doCache(){};

    @Pointcut("@annotation(com.cy.pj.common.annotation.ClearCache)")
    public void doClearCache(){};

    /*增删改清除缓存*/
    @AfterReturning("doClearCache()")
    public void ClearCache(JoinPoint joinPoint){
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        ClearCache annotation = method.getAnnotation(ClearCache.class);
        System.out.println("当前用户已经进行"+annotation.value()+" 缓存正在清除~");
        cache.clear();
        System.out.println("缓存已经清除~");
    }

    /**
     * 添加缓存
     */
    @Around("doCache()")
    public Object doAroundCache(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Class targetClass = proceedingJoinPoint.getTarget().getClass();
        System.out.println("targetClass: " + targetClass);
        MethodSignature methodSignature =
                (MethodSignature) proceedingJoinPoint.getSignature();
        System.out.println("methodSignature: " + methodSignature);
        Method method = methodSignature.getMethod();
        System.out.println("method: " + method);
        Method targetMethod = targetClass.getMethod(methodSignature.getName(),
                methodSignature.getParameterTypes());
        System.out.println("targetMethod: " + targetMethod);
        /*
        key:
        包名.类名.方法名(class java.lang.String, class java.lang.Integer)
        包名.类名.方法名(String, Integer)
        包名.类名.方法名(String username,Integer pageCurrent)
        包名.类名.方法名("",1)
         */
        String className = targetClass.getName();
        System.out.println("className: " + className);
        String methodName = targetMethod.getName();
        System.out.println("methodName: " + methodName);
        Class[] classes = methodSignature.getParameterTypes();
        System.out.println(Arrays.toString(classes));
        String classMethodName = className + "." + methodName;
        System.out.println("classMethodName: " + classMethodName);
        String params1 = "";
        for(int i = 0; i < classes.length; i++){
            System.out.println(classes[i].toString());
            String typeClass = classes[i].toString();
            String subType = typeClass.substring(typeClass.lastIndexOf(".") + 1);
            System.out.println("subType: " + subType);
            params1 += subType;
            if(i != classes.length - 1){
                params1 += ", ";
            }
        }
        String key1 = classMethodName + "(" + params1 + ")";
        System.out.println("key1 : " + key1);

        Parameter[] parameters = targetMethod.getParameters();
        System.out.println(Arrays.toString(parameters));
        String params2 = "";
        for(int i = 0; i < parameters.length; i++){
            String param = parameters[i].toString().
                    substring(parameters[i].toString().lastIndexOf(".") + 1);
            params2 += param;
            if(i != parameters.length - 1){
                params2 += ", ";
            }
        }
        String key2 = classMethodName + "(" + params2 + ")";
        System.out.println("key2 : " + key2);

        Object[] args = proceedingJoinPoint.getArgs();
        System.out.println(Arrays.toString(args));
        String params = new ObjectMapper().writeValueAsString(args);
        System.out.println("params: " + params);
        params = params.replace("[", "(")
                .replace("]", ")");
        System.out.println("params: " + params);
        String key = classMethodName + params;
        System.out.println("key: " + key);

        RequiredCache requiredCache = targetMethod.getAnnotation(RequiredCache.class);
        String requiredCacheValue = requiredCache.value();
        System.out.println("requiredCacheVale: " + requiredCacheValue);

        Object result = cache.get(key);
        if(result != null){
            System.out.println("从缓存总获取数据，返回给（动态）代理对象...");
            return result;
        }
        System.out.println("缓存中不存在对应的数据，查询数据库获取数据...");
        result = proceedingJoinPoint.proceed();
        System.out.println("将从数据库中提取的数据，存入(AOP)缓存...");
        cache.put(key, result);

        System.out.println("当前缓存数据：");
        Set<String> keys =  cache.keySet();
        for(String k : keys){
            Object value = cache.get(k);
            System.out.println("key: " +  k);
            System.out.println("value: " + value);
        }
        return result;
    }

    /*@Around("doCache()")
    public Object cacheAspect(ProceedingJoinPoint joinPoint) throws Throwable {

        *//*获取当前目标类的类对象*//*
        Class<?> targetClass = joinPoint.getTarget().getClass();
        *//*获取当前连接点签名对象 用于获取方法信息 例如：方法名、方法参数等*//*
        *//*方法名（methodSignature.getName()）
            方法所在的类（methodSignature.getDeclaringType()）
            返回类型（methodSignature.getReturnType()）
            参数类型数组（methodSignature.getParameterTypes()）
            参数名称（如果可用，通过特定方法获取）*//*
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        *//*通过getMethod获取当前方法对象 传入参数为(方法名、方法参数类型)*//*
        *//*方法签名对象.getMethod*//*
        Method method1 = signature.getMethod();
        *//*方法目标类对象.getMethod()*//*
        Method method = targetClass.getMethod(signature.getName(), signature.getParameterTypes());

        System.out.println(method1);
        System.out.println(method);

        RequiredCache annotation = method.getAnnotation(RequiredCache.class);
        String value = "";
        if (annotation != null){
            value = annotation.value();
        }

        Object[] data = joinPoint.getArgs();
        String params = "";
        for (int i = 0; i < data.length; i++) {
            params += data[i];
            if (i < data.length-1){
                params += ",";
            }
        }

        //类名.方法名(Sysdept sysdept)
        String key1 = targetClass.getName() + "." + signature.getName();
        String key = targetClass.getName() + "." + signature.getName() + "(" + params + ")";
        System.out.println(key);
        System.out.println(key1);
        Object result = cache.get(key);
        *//*如果缓存中数据有值 则返回缓存中数据 不去执行核心业务*//*
        if (result != null){
            System.out.println("当前数据为缓存中获取~~~");
            return result;
        }
        System.out.println("缓存中获取失败，此次数据从数据库获取，并且存入缓存中~");
        *//*没有值则去执行核心业务 并将返回值存储到缓存中*//*
        result = joinPoint.proceed();
        cache.put(key,result);
        return result;
    }
*/

}
